package com.shirotest.component;

import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.Filter;

import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.shirotest.shiro.MyCredentialsMatcher;
import com.shirotest.shiro.MyRolesAuthorizationFilter;
import com.shirotest.shiro.MySessionManager;
import com.shirotest.shiro.MyrSessionDAO;
import com.shirotest.shiro.MyShiroRealm;

@Configuration
public class ShiroConfigurer {
	/**
	 * Shiro的Web过滤器Factory 命名:shiroFilter
	 */
	@Bean(name = "shiroFilter")
	public ShiroFilterFactoryBean shiroFilterFactoryBean(org.apache.shiro.mgt.SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		// Shiro的核心安全接口,这个属性是必须的
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		
		
		//如果没有登录则会跳转到这里设置的url，注意登陆页不需要在下面再设置权限，设置了也无效
		shiroFilterFactoryBean.setLoginUrl("/login/login.html");
		//设置无权限跳转界面,此处一般不生效,一般自定义异常
		shiroFilterFactoryBean.setUnauthorizedUrl("/login/auth.html");
		
		//设置过滤器
		Map<String, Filter> filterMap = new LinkedHashMap<>();
		//设置自定义过滤器名称
		filterMap.put("MyRolesAuth", new MyRolesAuthorizationFilter());
		//filterMap.put("MyModularRealm", new MyModularRealmAuthorizer());
		shiroFilterFactoryBean.setFilters(filterMap);
		
		
		//此处使用的集合一定是要有序的，因为权限过滤器authc会从第一个开始匹配，如果无序则无法保证从第一个开始匹配
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
		
		filterChainDefinitionMap.put("/logout", "logout");
		
		//设置静态资源无需权限控制
        filterChainDefinitionMap.put("/**/*.js", "anon");
        filterChainDefinitionMap.put("/**/*.png", "anon");
        filterChainDefinitionMap.put("/**/*.jpg", "anon");
        filterChainDefinitionMap.put("/**/*.ico", "anon");
        filterChainDefinitionMap.put("/**/*.css", "anon");
        
        //设置登陆资源无需权限控制
        filterChainDefinitionMap.put("/login/*", "anon");
        
        filterChainDefinitionMap.put("/message/getMessage.do", "MyRolesAuth[A,B]");
        
        //放在最后，表示其它任何资源都需要登陆后才能访问
		filterChainDefinitionMap.put("/**", "authc");
		
		
		
		/*
		 * 过滤链定义，从上向下顺序执行，一般将 /**放在最为下边; authc:所有url都必须认证通过才可以访问;
		 * anon:所有url都都可以匿名访问
		 */
//		filterChainDefinitionMap.put("/login/login.html", "authc");
//		filterChainDefinitionMap.put("/ARole", "perms[ARole:select]");
//		filterChainDefinitionMap.put("/BRole", "perms[BRole:select]");
//		filterChainDefinitionMap.put("/PRole", "anon");
//		
//		
//		filterChainDefinitionMap.put("/shiro/login.do", "anon");
//		filterChainDefinitionMap.put("/js/**", "anon");
//		
//		filterChainDefinitionMap.put("/logout", "logout");

		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;
	}
	
	 @Bean
    public CookieRememberMeManager rememberMeManager(){
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
        cookieRememberMeManager.setCipherKey("1234567890123456".getBytes());
        return cookieRememberMeManager;
    }

    @Bean
    public SimpleCookie rememberMeCookie(){
        //这个参数是cookie的名称，对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("myCookie");
        //setcookie的httponly属性如果设为true的话，会增加对xss防护的安全系数。它有以下特点：
        //setcookie()的第七个参数
        //设为true后，只能通过http访问，javascript无法访问
        //防止xss读取cookie
        simpleCookie.setHttpOnly(true);
        simpleCookie.setPath("/");
        //记住我cookie生效时间 ,单位秒
        simpleCookie.setMaxAge(120);
        return simpleCookie;
    }
	
	/**
	 * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
		return authorizationAttributeSourceAdvisor;
	}
	
	
	/**
	 * 权限管理
	 */
	@Bean
	public org.apache.shiro.mgt.SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(MyShiroRealm());
		securityManager.setSessionManager(sessionManager());
		securityManager.setRememberMeManager(rememberMeManager());
		return securityManager;
	}
	
	/**
	 * Shiro Realm 继承自AuthorizingRealm的自定义Realm,即指定Shiro验证用户登录的类为自定义的
	 */
	@Bean
	public MyShiroRealm MyShiroRealm() {
		MyShiroRealm userRealm = new MyShiroRealm();
		userRealm.setCredentialsMatcher(new MyCredentialsMatcher());
		return userRealm;
	}
	
	
	@Bean(name = "sessionManager")
	public DefaultWebSessionManager sessionManager() {
        MySessionManager sessionManager = new MySessionManager();
        sessionManager.setSessionDAO(new MyrSessionDAO());
        sessionManager.setGlobalSessionTimeout(60*1000);
        return sessionManager;
    }
}
